home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.01 Jan 89 / LightTrace / LightTrace.p < prev    next >
Encoding:
Text File  |  1988-09-15  |  9.9 KB  |  484 lines  |  [TEXT/PJMM]

  1. unit LightTrace;
  2.  
  3. interface
  4.  
  5.     procedure InitTracing;{ call this to init Trace vars to safe values }
  6.  
  7.     procedure StartTracing (toText, toScreen, toFile: boolean);{ Start tracing all Subroutines }
  8.  
  9.     procedure EndTracing;{ return to normal operation }
  10.  
  11.     procedure WriteComment (Str: str255);{ write Str to Trace output }
  12.  
  13. { The 'Of' functions are useful when formatting output that must be a Str255. }
  14. { Also, try them in your observe window. eg. Rectof(ThePort^.ClipRgn^^.RgnBBox) }
  15.  
  16.     function IntOf (Int: longint): str255;{ convert the Int to a Decimal Str255 }
  17.  
  18.     function HexOf (lll: longint): str255;{ convert the Int to a Hex Str255 }
  19.  
  20.     function PointOf (fff: Point): str255;{ convert the Point to a Str255 }
  21.  
  22.     function RectOf (R: Rect): str255;{ convert the Rect to a Str255 }
  23.  
  24.     procedure TraceProcTop;{ don't call this yourself}
  25.  
  26.     procedure TraceProcBot;{ don't call this yourself}
  27.  
  28. implementation
  29.  
  30.     type
  31.         intsArr = array[0..16000] of integer;
  32.         intsArrP = ^intsArr;
  33.  
  34.     var
  35.         indent: integer;
  36.         OldTrap7, OldTrap8: longint;
  37.         doText, doScreen, doFile, started: boolean;
  38.         ScreenWindow: grafPtr;
  39.         TracePB: paramBlockRec;
  40.  
  41.  
  42.     procedure ScanForRts (var iP: intsArrP);
  43.     forward;
  44.  
  45.     procedure ReplaceTrap7;
  46.     external;
  47.     procedure ReplaceTrap8;
  48.     external;
  49.  
  50.  
  51.     function GetRTS: longint;
  52.     inline
  53.         $2EAE, $0004;
  54.  
  55.     function IntOf; {(int : longint) : str255}
  56.         var
  57.             str: str255;
  58.     begin
  59.         NumToString(int, str);
  60.         IntOf := str;
  61.     end;
  62.  
  63.     function HexOf; { (lll : longint) : str255}
  64.         var
  65.             str, str2: str255;
  66.             i: integer;
  67.             c: char;
  68.     begin
  69.         if lll = 0 then
  70.             str := '$0'
  71.         else
  72.             begin
  73.                 str := '';
  74.                 while (lll <> 0) do
  75.                     begin
  76.                         i := lll mod 16;
  77.                         if i < 10 then
  78.                             c := chr(ord('0') + i)
  79.                         else
  80.                             c := chr(ord('A') + (i - 10));
  81.                         str2 := 'x';
  82.                         str2[1] := c;
  83.                         str := concat(str2, str);
  84.                         lll := BitShift(lll, -4);
  85.                     end;
  86.                 str := concat('$', str)
  87.             end;
  88.         HexOf := str;
  89.     end;
  90.  
  91.  
  92.     function Pointof;{  (fff :  Point) : str255}
  93.         var
  94.             str: str255;
  95.     begin
  96.         str := concat(IntOf(fff.h), ' ', IntOf(fff.v));
  97.         Pointof := str;
  98.     end;
  99.  
  100.  
  101.     function RectOf; {(R : Rect) : str255}
  102.         var
  103.             str: str255;
  104.     begin
  105.         with R do
  106.             str := concat(Intof(left), ' ', Intof(top), ' ', Intof(right), ' ', Intof(bottom), ' ');
  107.         RectOf := str;
  108.     end;
  109.  
  110.  
  111.     procedure InitTracing;
  112.     begin
  113.         started := false;
  114.         doText := true;
  115.         doScreen := false;
  116.         doFile := false;
  117.         indent := 0;
  118.     end;
  119.  
  120. { Open a small window in the back to see our output }
  121. { set ScreenWindow to point to this window }
  122.     procedure MakeScreenWindow;
  123.         var
  124.             r: rect;
  125.             OldPort: GrafPtr;
  126.     begin
  127.         getPort(OldPort);
  128.         setRect(r, 4, 40, 156, 140);
  129.         ScreenWindow := NewWindow(nil, r, 'Trace Info', true, 0, nil, false, 0);
  130.         setport(ScreenWindow);
  131.         textmode(srccopy);
  132.         textFont(1);
  133.         textsize(9);
  134.         textFont(4);{monaco}
  135.         moveto(4, 16);
  136.         setport(OldPort);
  137.     end;
  138.  
  139. { remove ScreenWindow from the screen and from memory }
  140.     procedure RemoveScreenWindow;
  141.     begin
  142.         if doScreen then
  143.             DisposeWindow(ScreenWindow);
  144.     end;
  145.  
  146. { do this to write a cr to the screen }
  147.     procedure ScreenLn;
  148.         var
  149.             ThePen, poi: point;
  150.             r: rect;
  151.             aRgn: RgnHandle;
  152.             OldPort: GrafPtr;
  153.     begin
  154.         GetPort(OldPort);
  155.         SetPort(ScreenWindow);
  156.         r := ScreenWindow^.PortRect;
  157.         GetPen(ThePen);
  158.         ThePen.h := r.left + 4;
  159.         ThePen.v := ThePen.v + 12; { move thePen down }
  160.         if (ThePen.v + 12) > r.bottom then
  161.             begin { scroll up if necessary }
  162.                 aRgn := NewRgn;
  163.                 ScrollRect(r, 0, -12, aRgn);
  164.                 DisposeRgn(aRgn);
  165.                 ThePen.v := ThePen.v - 12;
  166.                 setorigin(0, 0);
  167.                 repeat { pause feature }
  168.                     GetMouse(poi);
  169.                 until not ptInRect(poi, r);
  170.             end;
  171.         moveto(ThePen.h, ThePen.v);
  172.         setPort(OldPort);
  173.     end;
  174.  
  175. { This does a Write to our window }
  176.     procedure WriteScreen (str: str255);
  177.         var
  178.             ThePen: point;
  179.             r: rect;
  180.             OldPort: GrafPtr;
  181.             cr: str255;
  182.     begin
  183.         cr := 'x';
  184.         cr[1] := chr(13);
  185.         GetPort(OldPort);
  186.         SetPort(ScreenWindow);
  187.         r := ScreenWindow^.PortRect;
  188.         GetPen(ThePen);
  189.         if (ThePen.h + stringwidth(str) > r.right) or (pos(cr, str) > 0) then
  190.             ScreenLn;
  191.         DrawString(str);
  192.         SetPort(OldPort);
  193.     end;
  194.  
  195. { This does a WriteLn to our window }
  196.     procedure WriteScreenLn (str: str255);
  197.         var
  198.             i: integer;
  199.             ThePen: point;
  200.             r: rect;
  201.             OldPort: GrafPtr;
  202.     begin
  203.         GetPort(OldPort);
  204.         SetPort(ScreenWindow);
  205.         WriteScreen(str);
  206.         ScreenLn;
  207.         SetPort(OldPort);
  208.     end;
  209.  
  210.  
  211.     procedure MakeTraceFile;
  212.         var
  213.             err: integer;
  214.             str: str255;
  215.     begin
  216.         str := 'Trace_File';
  217.         with TracePB do
  218.             begin
  219.                 ioCompletion := nil;
  220.                 ioNamePtr := @str;
  221.                 ioVRefNum := 0;
  222.                 ioVersNum := 0;
  223.                 ioPermssn := 0;
  224.                 ioMisc := nil;
  225.                 err := PBOpen(@TracePB, false);
  226.                 if err = fnfErr then
  227.                     begin
  228.                         err := PBCreate(@TracePB, false);
  229.                         if err = 0 then
  230.                             err := PBOpen(@TracePB, false);
  231.                     end;
  232.                 if err = 0 then
  233.                     begin
  234.                         ioMisc := pointer(0);
  235.                         err := PBSetEOF(@TracePB, false);
  236.                         if err = 0 then
  237.                             begin
  238.                                 err := PBGetFInfo(@TracePB, false);
  239.                                 if err = 0 then
  240.                                     with TracePB.ioFlFndrInfo do
  241.                                         begin
  242.                             { we'll make this an MPW text file }
  243.                                             fdType := 'TEXT';
  244.                                             fdCreator := 'MPS ';
  245.                                             err := PBSetFInfo(@TracePB, false);
  246.                                         end;{ with finder info }
  247.                             end;{ if getFinfo OK }
  248.                     end { if open OK }
  249.                 else
  250.                     doFile := false;
  251.             end; { with TracePB }
  252.     end;{ proc MakeTraceFile }
  253.  
  254.  
  255.     procedure CloseTraceFile;
  256.         var
  257.             err: integer;
  258.     begin
  259.         if doFile then
  260.             err := PBClose(@TracePB, false);
  261.     end;
  262.  
  263. { same as write except the str goes to the file }
  264.     procedure WriteFile (str: str255);
  265.         var
  266.             err: integer;
  267.             eof: longint;
  268.     begin
  269.         if length(str) > 0 then
  270.             if doFile then
  271.                 with TracePB do
  272.                     begin
  273.                         err := PBGetEof(@TracePB, false);{ ever Fail??}
  274.  
  275.                         if err <> 0 then
  276.                             repeat
  277.                                 sysbeep(1)
  278.                             until button;
  279.  
  280.                         eof := ord(ioMisc);
  281.                         ioMisc := pointer(eof + length(str));
  282.                         err := PBSetEof(@TracePB, false);
  283.                         if err = 0 then
  284.                             begin
  285.                                 ioBuffer := pointer(ord(@str) + 1);
  286.                                 ioReqCount := length(str);
  287.                                 ioPosMode := fsFromstart;
  288.                                 ioPosOffset := eof;
  289.                                 err := PBWrite(@TracePB, false);
  290.                             end;{ setEof OK }
  291.                     end;{ with TracePB }
  292.     end;{ proc WriteFile }
  293.  
  294.  
  295. { same as writeLn(str) except output is to the file}
  296.     procedure WriteFileLn (str: str255);
  297.     begin
  298.         writeFile(str);
  299.         str := 'x';
  300.         str[1] := chr(13);
  301.         writeFile(str);
  302.     end;
  303.  
  304.  
  305. { These two proc's are our output bottleneck }
  306.  
  307.     procedure WriteStr (str: str255);
  308.     begin
  309.         if doText then
  310.             Write(str);
  311.         if doScreen then
  312.             WriteScreen(str);
  313.         if doFile then
  314.             WriteFile(str);
  315.     end;
  316.  
  317.     procedure WriteStrLn (str: str255);
  318.     begin
  319.         if dotext then
  320.             WriteLn(str);
  321.         if doScreen then
  322.             WriteScreenLn(str);
  323.         if doFile then
  324.             WriteFileLn(str);
  325.     end;
  326.  
  327.  
  328. { Call ScanForRTS to find the end of a procedure.  iP is pointed }
  329. { past the end (at the name) }
  330. { Copy the name into the str.  If it is a MacApp name (16 char), }
  331. { then add more. }
  332.     procedure GetTheName (var iP: intsArrP;
  333.                                     var str: str255);
  334.     begin
  335.         str := '12345678';
  336.         ScanForRts(iP);
  337.         blockMove(@iP^, pointer(ord(@str) + 1), 8);
  338.         if ord(str[1]) >= 128 then
  339.             str[1] := chr(ord(str[1]) - 128);
  340.         if ord(str[2]) >= 128 then
  341.             begin
  342.                 str[2] := chr(ord(str[2]) - 128);
  343.                 str := concat(str, '12345678');
  344.                 blockMove(pointer(ord(@iP^) + 8), pointer(ord(@str) + 9), 8);
  345.             end;
  346.     end;
  347.  
  348.  
  349.     procedure TraceProcTop;
  350.         var
  351.             str: str255;
  352.             iP: intsArrP;
  353.             i: integer;
  354.     begin
  355.         iP := pointer(GetRTS);
  356.         GetTheName(iP, str);
  357.  
  358.         for i := 1 to indent do
  359.             writeStr(' . ');
  360.         indent := indent + 1;
  361.  
  362.         writeStr('BEGIN ');
  363.         writeStrLn(str);
  364.     end;
  365.  
  366.  
  367.     procedure TraceProcBot;
  368.         var
  369.             str: str255;
  370.             iP: intsArrP;
  371.             i: integer;
  372.     begin
  373.         iP := pointer(GetRTS);
  374.         GetTheName(iP, str);
  375.  
  376.         indent := indent - 1;
  377.         for i := 1 to indent do
  378.             writeStr(' . ');
  379.  
  380.         writeStr('END   ');
  381.         writeStrLn(str);
  382.     end;
  383.  
  384.  
  385.     procedure WriteComment;{ (str : str255)}
  386.         var
  387.             i: integer;
  388.     begin
  389.         for i := 1 to indent do
  390.             writeStr(' . ');
  391.         writeStr('REM ');
  392.         writeStrLn(str);
  393.     end;
  394.  
  395.     procedure ScanForRts; { (var iP : intsArrP)}
  396.         var
  397.             count, size: longint;
  398.             str: str255;
  399.     begin
  400.         count := 4000;{ max size of any procedure ?? }
  401.         size := 0;
  402.         while size = 0 do
  403.             begin
  404.                 if iP^[0] = $4E5E then                            { UNLK }
  405.                     begin
  406.                         if (iP^[1] = $2E9F) and (iP^[2] = $4E75) then    { MOVE.l (A7)+,A7  RTS}
  407.                             size := 6
  408.                         else if iP^[1] = $4E75 then                        { RTS }
  409.                             size := 4
  410.                         else if iP^[1] = $205F then                        { MOVEA.L (A7)+,A0 }
  411.                             begin
  412.                                 if (iP^[2] = $4FEF) and (iP^[4] = $4ED0) then        { LEA x(A7),A7  JMP (A0) }
  413.                                     size := 10
  414.                                 else if (iP^[2] = $DFFC) and (iP^[5] = $4ED0) then    { ADD.l #x,A7  JMP (A0) }
  415.                                     size := 12
  416.                                 else if (iP^[2] = $DEFC) and (iP^[4] = $4ED0) then    { ADD.w #x,A7  JMP (A0) }
  417.                                     size := 10
  418.                                 else if iP^[3] = $4ED0 then                            {JMP (A0) }
  419.                                     size := 8
  420.                             end;
  421.                     end;
  422.                 count := count - 2;
  423.                 if count <= 0 then
  424.                     size := 22222;
  425.                 if size <> 0 then
  426.                     iP := pointer(ord(iP) + size)
  427.                 else
  428.                     iP := pointer(ord(iP) + 2)
  429.             end;{ while size=0 }
  430.         if count <= 0 then
  431.             begin
  432.                 str := 'unknown';
  433.                 iP := pointer(ord(@str) + 1);
  434.             end;
  435.     end; { proc scan for Rts }
  436.  
  437.  
  438.     procedure StartTracing; { (toText, toScreen, toFile : boolean)}
  439.         var
  440.             lP: ^longint;
  441.     begin
  442.         InitTracing;{ initialize global vars }
  443.  
  444. { save the options as globals }
  445.         doText := toText;
  446.         doScreen := toScreen;
  447.         doFile := toFile;
  448.  
  449.         started := true;
  450.  
  451.         if doscreen then
  452.             MakeScreenWindow;
  453.         if doFile then
  454.             MakeTraceFile;
  455.         if doText then
  456.             ShowText;
  457.  
  458.         lP := pointer($80 + 4 * 7);{ trap 7}
  459.         OldTrap7 := lP^;
  460.         lP^ := ord(@ReplaceTrap7);
  461.         lP := pointer($80 + 4 * 8);{ trap 8}
  462.         OldTrap8 := lP^;
  463.         lP^ := ord(@ReplaceTrap8);
  464.  
  465.     end;{ proc StartTracing }
  466.  
  467.     procedure EndTracing;
  468.         var
  469.             lP: ^longint;
  470.     begin
  471.         if Started then
  472.             begin
  473.                 lP := pointer($80 + 4 * 7);{ trap 7}
  474.                 lP^ := OldTrap7;
  475.                 lP := pointer($80 + 4 * 8);{ trap 8}
  476.                 lP^ := OldTrap8;
  477.                 RemoveScreenWindow;
  478.                 CloseTraceFile;
  479.             end;
  480.         InitTracing;
  481.     end;{ proc EndTracing }
  482.  
  483.  
  484. end.